﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Threading.Tasks;
using System.Threading;

namespace UFrameWork
{
    public class WaitForAction
    {
        /// <summary>
        /// 多线程锁
        /// </summary>
        private static object locked = new object();

        /// <summary>
        /// WaitForAction 存储类
        /// </summary>
        private static Dictionary<string, List<WaitForAction>> map = new Dictionary<string, List<WaitForAction>>();

        /// <summary>
        /// 全局默认超时时间
        /// </summary>
        private static int defaultTimeOut = 5;

        /// <summary>
        /// 超时时间
        /// </summary>
        private int timeOut = 0;

        /// <summary>
        /// 是否结束
        /// </summary>
        private bool isEnd = false;

        /// <summary>
        /// 传入对的参数
        /// </summary>
        private object[] param;

        /// <summary>
        /// 返回数据
        /// </summary>
        private object[] result;

        /// <summary>
        /// 启动时间
        /// </summary>
        private DateTime startTime = DateTime.Now;

        /// <summary>
        /// Key
        /// </summary>
        public string Key { get; private set; }

        /// <summary>
        /// 是否为执行超时
        /// </summary>
        public bool IsTimeOut { get; private set; }

        /// <summary>
        /// 等待Action执行结果
        /// </summary>
        /// <param name="key">key</param>
        /// <param name="param">参数</param>
        public WaitForAction(string key,object param = null)
        {
            Key = key;
            if (!map.ContainsKey(key))
            {
                map[key] = new List<WaitForAction>();
            }
            map[key].Add(this);
            timeOut = defaultTimeOut;
            IsTimeOut = false;
        }

        /// <summary>
        ///  获取返回结果
        /// </summary>
        /// <typeparam name="T">返回类型</typeparam>
        /// <param name="index">参数索引:从1开始</param>
        /// <returns></returns>
        public T Result<T>(int index = 1)
        {
            return (T)result[index - 1];
        }

        /// <summary>
        /// 传进来的参数
        /// </summary>
        /// <typeparam name="T">返回类型</typeparam>
        /// <param name="index">参数索引:从1开始</param>
        /// <returns></returns>
        public T Param<T>(int index = 1)
        {
            return (T)param[index - 1];
        }

        /// <summary>
        /// 查找
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public static List<WaitForAction> Find(string key)
        {
            if (map.ContainsKey(key))
            {
                return map[key];
            }

            return new List<WaitForAction>();
        }

        /// <summary>
        /// 循环处理
        /// </summary>
        public static void Each(string key,Action<WaitForAction> handle)
        {
            lock (locked)
            {
                if (map.ContainsKey(key))
                {
                    for (int i = map[key].Count - 1; i >= 0; i--)
                    {
                        handle(map[key][i]);
                    }
                }
            }
        }

        /// <summary>
        /// 结束异步
        /// </summary>
        public void EndWait(params object[] result)
        {
            map[Key].Remove(this);
            isEnd = true;
            this.result = result;
        }

        /// <summary>
        /// 结束key下所有异步方法
        /// </summary>
        /// <param name="key"></param>
        /// <param name="result">返回结果,不定个数参数</param>
        public static void End(string key, params object[] result)
        {
            WaitForAction.Each(key, (WaitForAction v) => { v.EndWait(result); });
        }

        /// <summary>
        /// 全局默认超时时间
        /// </summary>
        /// <param name="time"></param>
        public static void DefaultTimeOut(int time)
        {
            defaultTimeOut = time;
        }


        /// <summary>
        /// 等待方法返回
        /// </summary>
        /// <param name="second">超时时间:0使用默认超时时间</param>
        /// <returns></returns>
        public Task Wait(int second = 0)
        {
            if (second > 0)
            {
                this.timeOut = second;
            }

            return Task.Run(() => 
            {
                while (true)
                {
                    Thread.Sleep(100);

                    if ((DateTime.Now - startTime).Seconds >= timeOut)
                    {
                        IsTimeOut = true;
                        return;
                    }

                    if (isEnd)
                    {
                        return;
                    }
                }
            });
        }
    }
}